﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using eLuk.Runtime;
using eLuk.Entity;
using eLuk.Data;
using eLuk.Common;
using Windows.ApplicationModel.Activation;
using Windows.Storage;
using Windows.Storage.Streams;
using System.IO;
using System.Runtime.Serialization;

namespace eLuk
{
	public delegate void eLukComponentUpdated( object sender, eLukComponentUpdatedEventArgs e );
	public class eLukComponentUpdatedEventArgs : EventArgs
	{
		public OperationOption Option { get; set; }
		public string Message { get; set; }

		public eLukComponent eLukComponent { get; set; }
	}

	sealed partial class App
	{
		private static eLuk.Security.DataProtection DataProtection = new Security.DataProtection();
		public static bool eLukComponentFound { get; set; }
		public static bool eLukUserCredentialExists { get; set; }
		public static bool eLukLocalLoginStatus { get; set; }

		public static event eLukComponentUpdated eLukComponentUpdated;
		public static IMAPSession IMAPSession { get; set; }
		public static eLuk.Entity.eLukComponent eLukComponent { get; set; }
		public static async Task IniteLuk( string IMAPServer, string Port, string EmailID, string Password )
		{
			App.eLukComponent = await App.ReadIMAPFolder( EmailID );
			//App.WriteeLukGroup(App.eLukComponent.)
			Windows.Security.Credentials.PasswordCredential credential = await App.ReadVault( EmailID );
			App.eLukLocalLoginStatus = false;

			if ( App.eLukComponent == null )
			{
				App.eLukComponentFound = false;
				App.eLukComponent = await eLukDataSource.GetComponentAsync();
				EmailAccount emailAccount = new EmailAccount();
				emailAccount.UserName = EmailID;
				emailAccount.Password = Password;
				emailAccount.IMAPFolder = null;
				App.eLukComponent.SubComponents.Find( g => g.UniqueId == "email" ).eLukObject = emailAccount;
			}
			else
			{
				App.eLukComponentFound = true;
			}

			if ( credential != null )
			{
				App.eLukUserCredentialExists = true;
			}

			if ( App.eLukUserCredentialExists && App.eLukComponentFound )
			{
				App.eLukLocalLoginStatus = await App.ValidateCredentials( credential );
			}

			if ( App.eLukLocalLoginStatus )
			{
				await App.InitSession( IMAPServer, Port, EmailID, Password );
			}
		}
		public async static Task InitSession( string IMAPServer, string Port, string EmailID, string Password )
		{
			IMAPServer = "imap.gmail.com";
			Port = "993";
			eLuk.CommandEngine.EmailServer _server = null;
			await Task.Run( () =>
			{
				_server = new eLuk.CommandEngine.EmailServer( IMAPServer, Port );
				_server.Credential.User = EmailID;
				_server.Credential.Password = Password;
				App.IMAPSession = new Runtime.IMAPSession( _server );
			} );
			App.IMAPSession.IMAPObjectUpdated += Session_IMAPObjectUpdated;
		}
		public static async Task<MemoryStream> SerializeAndProtect( eLuk.Entity.eLukComponent group )
		{
			MemoryStream memory = new MemoryStream();
			DataContractSerializer serializer = new
									DataContractSerializer( group.GetType() );
			try
			{
				serializer.WriteObject( memory, group );
				memory.Position = 0;
				memory = await App.DataProtection.Protect( "LOCAL=user", memory );
				memory.Position = 0;
			}
			catch ( Exception ex )
			{ }
			return memory;
		}
		public static async Task<eLuk.Entity.eLukComponent> UnprotectAndSerialize( IInputStream stream )
		{
			Stream unprotectedSteam = null;
			DataContractSerializer serializer = new
									DataContractSerializer( typeof( eLuk.Entity.eLukComponent ) );
			eLuk.Entity.eLukComponent o = null;
			try
			{
				unprotectedSteam = await App.DataProtection.UnProtect( "LOCAL=user", stream );
				o = serializer.ReadObject( unprotectedSteam ) as eLuk.Entity.eLukComponent;
			}
			catch ( Exception ex )
			{ }
			return o;
		}
		private static async Task<eLuk.Entity.eLukComponent> ReadIMAPFolder(string User)
		{

			StorageFolder folder = null;
			StorageFile file = null;

			try
			{
				try
				{
					folder = await ApplicationData.Current.LocalFolder.GetFolderAsync( "eLuk" );
				}
				catch ( FileNotFoundException )
				{
					return null;
				}
				catch ( Exception ex )
				{
					return null;
				}

				if ( folder == null )
					folder = await ApplicationData.Current.LocalFolder.GetFolderAsync( "eLuk" );

				if ( folder != null )
				{
					file = await folder.GetFileAsync( User + ".eLuk" );
					using ( IInputStream stream = await file.OpenSequentialReadAsync() )
					{
						return await App.UnprotectAndSerialize( stream );
					}
				}
				else
				{
					return null;
				}
			}
			catch ( FileNotFoundException fnf )
			{
				return null;
			}
			catch ( Exception ex )
			{
				throw new Exception( "Unable to load the eLuk email object." );
			}
		}
		private static async void Session_IMAPObjectUpdated( object sender, Runtime.IMAPObjectUpdatedEventArgs e )
		{
			if ( e.OperationOption == OperationOption.WriteToDisk )
			{
				EmailAccount emailAccount = App.eLukComponent.SubComponents.Find( g => g.UniqueId == "email" ).eLukObject as EmailAccount;
				//emailAccount.UserName = IMAPSession.Engine.Channel.Server.Credential.User;
				emailAccount.Password = IMAPSession.Engine.Channel.Server.Credential.Password;
				emailAccount.IMAPFolder = e.IMAPObject as eLukFolder;
				App.eLukComponent.SubComponents.Find( g => g.UniqueId == "email" ).eLukObject = emailAccount;
				await App.WriteeLukGroup(IMAPSession.Engine.Channel.Server.Credential.User, App.eLukComponent );
			}
			else if ( e.OperationOption == OperationOption.CompareFolders )
			{

			}

			if ( App.eLukComponentUpdated != null )
			{
				eLukComponentUpdatedEventArgs elcuea = new eLukComponentUpdatedEventArgs();
				elcuea.Option = e.OperationOption;
				elcuea.Message = e.Message == null ? "" : e.Message;
				elcuea.eLukComponent = App.eLukComponent;
				App.eLukComponentUpdated( sender, elcuea );
			}

		}
		private static async Task<bool> WriteeLukGroup( string User, eLuk.Entity.eLukComponent group )
		{

			if ( group == null )
				return false;

			bool result = true;

			StorageFolder folder = null;
			bool createFolder = false;
			bool createFile = false;
			StorageFile file = null;

			try
			{
				try
				{
					folder = await ApplicationData.Current.LocalFolder.GetFolderAsync( "eLuk" );
					createFolder = false;
				}
				catch ( Exception ex )
				{
					if ( ex is FileNotFoundException )
						createFolder = true;
				}
				if ( createFolder )
					folder = await ApplicationData.Current.LocalFolder.CreateFolderAsync( "eLuk" );

				if ( folder != null )
				{
					try
					{
						file = await folder.GetFileAsync( User + ".eLuk" );
						await file.DeleteAsync( StorageDeleteOption.Default );
						createFile = true;
					}
					catch ( Exception ex )
					{
						if ( ex is FileNotFoundException )
							createFile = true;
					}
				}

				if ( createFile )
					file = await folder.CreateFileAsync( User + ".eLuk" );

				if ( file.IsAvailable )
				{
					using ( Stream fileStream = await file.OpenStreamForWriteAsync() )
					{
						MemoryStream memory = await App.SerializeAndProtect( group );
						memory.Seek( 0, SeekOrigin.Begin );
						await memory.CopyToAsync( fileStream );
						await fileStream.FlushAsync();
					}
				}
			}
			catch ( Exception ex )
			{

			}

			return result;

		}
		public static async Task<bool> WriteVault( string UserName, string Password )
		{
			await Task.Run( () =>
			{
				Windows.Security.Credentials.PasswordVault vault = new Windows.Security.Credentials.PasswordVault();
				Windows.Security.Credentials.PasswordCredential credential = new Windows.Security.Credentials.PasswordCredential(
					"teavch.eLuk.Account", UserName, Password );
				vault.Add( credential );
			} );
			return true;
		}
		public static async Task<Windows.Security.Credentials.PasswordCredential> ReadVault( string UserName )
		{
			IReadOnlyList<Windows.Security.Credentials.PasswordCredential> credentials = null;
			Windows.Security.Credentials.PasswordCredential credential = null;
			try
			{
				await Task.Run( () =>
				{
					Windows.Security.Credentials.PasswordVault vault = new Windows.Security.Credentials.PasswordVault();
					credentials = vault.FindAllByResource( "teavch.eLuk.Account" );
					if ( credentials.Count > 0 )
						credential = credentials.FirstOrDefault( u => u.UserName == UserName );
				} );
			}
			catch ( Exception ex )
			{

			}
			return credential;
		}
		private static async Task<bool> ValidateCredentials( Windows.Security.Credentials.PasswordCredential credential )
		{
			bool _validation = false;
			EmailAccount account = App.eLukComponent.SubComponents.Find( g => g.UniqueId == "email" ).eLukObject as EmailAccount;
			await Task.Run( () =>
			{
				_validation = account.UserName == credential.UserName && account.Password == credential.Password;
			}
			);
			return _validation;
			//return true;
		}

	}
}
